from typing import List
from abc import ABC, abstractmethod
from datetime import datetime

import simplejson as json


class JobStateType(int):
    '''任务状态'''


INITIAL = JobStateType(0)  # 新建任务
RUNNING = JobStateType(1)  # 运行中
PENDING = JobStateType(2)  # 准备就绪
DONE = JobStateType(3)  # 终止执行


class Job:
    job_id: str
    state: JobStateType
    func_kwargs: dict
    sched_times: int
    create_time: datetime
    update_time: datetime

    def __init__(self,
                 job_id,
                 state,
                 func_kwargs,
                 sched_times,
                 create_time,
                 update_time,
                 **kwargs) -> None:
        self.job_id = job_id
        self.state = state
        self.func_kwargs = func_kwargs
        self.sched_times = sched_times
        self.create_time = datetime.fromtimestamp(create_time)
        self.update_time = datetime.fromtimestamp(update_time)

    def __str__(self) -> str:
        return f'<Job> {self.__dict__}'

    def __repr__(self) -> str:
        return self.__str__()


class NewJobModel:
    job_id: str
    func_name: str
    func_kwargs: dict

    def __init__(self, job_id, func_name, func_kwargs, **kwargs) -> None:
        self.job_id = job_id
        self.func_name = func_name
        self.func_kwargs = func_kwargs
        self.create_time = self._now().timestamp()

    def _now(self) -> datetime:
        return datetime.now()

    def get_data(self) -> dict:
        return {
            'job_id': self.job_id,
            'func_name': self.func_name,
            'func_kwargs': self.func_kwargs,
            'state': INITIAL,
            'create_time': self.create_time,
            'update_time': self.create_time,
            'sched_times': 0
        }


class JobStore(ABC):
    '''任务状态信息存储接口'''

    @abstractmethod
    def get_job(self, job_id: str) -> Job:
        '''
        获取任务状态信息
        :param str task_id: 任务ID
        '''

    @abstractmethod
    def create_job(self, job: NewJobModel) -> Job:
        '''创建新任务'''

    @abstractmethod
    def update_job_state(self, job: Job, state: JobStateType) -> Job:
        '''更新任务状态'''

    @abstractmethod
    def load_all_jobs(self) -> List[Job]:
        '''加载所有未终止执行的任务'''